package com.sishu.njrtsdms.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sishu.njrtsdms.annotation.Anonymous;
import com.sishu.njrtsdms.domain.core.Groups;
import com.sishu.njrtsdms.domain.core.PageInfo;
import com.sishu.njrtsdms.domain.core.R;
import com.sishu.njrtsdms.domain.dto.TcpPointAssignRecordDTO;
import com.sishu.njrtsdms.domain.dto.TeachConPrjAuditDTO;
import com.sishu.njrtsdms.domain.dto.TeachConPrjDTO;
import com.sishu.njrtsdms.domain.dto.TeachConPrjTmplDTO;
import com.sishu.njrtsdms.domain.vo.*;
import com.sishu.njrtsdms.exception.ServiceException;
import com.sishu.njrtsdms.jooq.codegen.tables.daos.TcpDeclareBelongYearConfigDAO;
import com.sishu.njrtsdms.service.TeachConPrjService;
import com.sishu.njrtsdms.service.TeachConPrjTmplService;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Workbook;
import org.jooq.types.ULong;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Year;
import java.util.List;
import java.util.Map;

/**
 * 申报控制器
 */
@Validated
@RestController
@RequestMapping("/declare")
@Slf4j
public class DeclareController {

    private final TeachConPrjService teachConPrjService;

    private final TeachConPrjTmplService teachConPrjTmplService;

    private final TcpDeclareBelongYearConfigDAO belongYearConfigDAO;

    private final ObjectMapper objectMapper;


    public DeclareController(TeachConPrjService teachConPrjService,
                             TeachConPrjTmplService teachConPrjTmplService,
                             TcpDeclareBelongYearConfigDAO belongYearConfigDAO,
                             ObjectMapper objectMapper) {
        this.teachConPrjService = teachConPrjService;
        this.teachConPrjTmplService = teachConPrjTmplService;
        this.belongYearConfigDAO = belongYearConfigDAO;
        this.objectMapper = objectMapper;
    }


    @GetMapping("/project/{tcpId}")
    public R<TeachConPrjVO> getTeachingConstructionProject(
            @PathVariable(required = false, name = "tcpId")
            Long tcpId) {
        var teachConPrjVO = teachConPrjService.queryOneTeachConPrj(tcpId);
        return R.ok(teachConPrjVO);
    }


    /**
     * 分页条件查询申报的教学建设项目信息
     *
     * @param teachConPrjDTO 教学建设项目查询条件
     * @return 教学建设项目分页信息
     */
    @GetMapping("/project/page")
    public R<PageInfo<TeachConPrjVO>> pageTeachingConstructionProject(TeachConPrjDTO teachConPrjDTO) {
        var teaConPrjVOPageInfo = teachConPrjService.page(teachConPrjDTO);
        return R.ok(teaConPrjVOPageInfo);
    }

    /**
     * 条件精确查询教学建设项目总数
     *
     * @param teachConPrjDTO 教学建设项目查询条件
     * @return 教学建设项目符合条件的总数
     */
    @GetMapping("/project/totalCount")
    public R<Long> TeachingConstructionProjectTotalCount(TeachConPrjDTO teachConPrjDTO) {
        Long teaConPrjVOTotalCount = teachConPrjService.totalCount(teachConPrjDTO);
        return R.ok(teaConPrjVOTotalCount);
    }

    @GetMapping("/projectTmpl/page")
    public R<PageInfo<TeachConPrjTmplVO>> ProjectTmplPage(TeachConPrjTmplDTO teachConPrjTmplDTO) {
        var ProjectTmplVOPageInfo = teachConPrjTmplService.page(teachConPrjTmplDTO);
        return R.ok(ProjectTmplVOPageInfo);
    }

    @GetMapping("/projectTmpl/totalCount")
    public R<Long> ProjectTmplTotalCount(TeachConPrjTmplDTO teachConPrjTmplDTO) {
        Long ProjectTmplVOTotalCount = teachConPrjTmplService.totalCount(teachConPrjTmplDTO);
        return R.ok(ProjectTmplVOTotalCount);
    }


    /**
     * 创建项目
     */
    @PostMapping("/project/create")
    public R<String> create(@RequestBody
                            @Validated({Groups.Add.class})
                            TeachConPrjDTO TeachConPrjDTO) {

        teachConPrjService.create(TeachConPrjDTO);
        return R.ok();
    }

    @PutMapping("/project/{tcpId}")
    public R<String> updateProject(@PathVariable(name = "tcpId")
                                   ULong tcpId,
                                   @Validated({Groups.Update.class})
                                   @RequestBody
                                   TeachConPrjDTO TeachConPrjDTO) {
        teachConPrjService.updateProject(tcpId, TeachConPrjDTO);
        return R.ok();
    }

    @DeleteMapping("/project/{tcpId}")
    public R<String> deleteProject(@PathVariable(name = "tcpId")
                                   ULong tcpId) {
        teachConPrjService.deleteProject(tcpId);
        return R.ok();
    }

    @PostMapping("/project/{tcpId}")
    public R<String> declare(@PathVariable(name = "tcpId")
                             ULong tcpId) {
        teachConPrjService.declare(tcpId);
        return R.ok();
    }




    /**
     * 上传申报项目文件
     */
    @PostMapping(value = "/project/uploadProjectFiles/{tcpId}")
    public R<String> uploadProjectFiles(@PathVariable(name = "tcpId")
                                        ULong tcpId,
                                        List<MultipartFile> files) {
        teachConPrjService.uploadProjectFiles(tcpId, files);
        return R.ok();
    }


    /**
     * 根据申报项目id查询所有项目文件信息
     *
     * @param tcpId 申报项目id
     */
    @GetMapping(value = "project/listProjectProofFiles/{tcpId}")
    public R<List<SysFileVO>> listProjectProofFiles(@PathVariable(value = "tcpId")
                                                    ULong tcpId) {
        List<SysFileVO> sysFileList = CollUtil.emptyIfNull(teachConPrjService.listProjectProofFiles(tcpId));
        return R.ok(sysFileList);
    }


    /**
     * 审核项目
     */
    @PostMapping(value = "project/audit/{tcpId}")
    public R<String> auditProject(@PathVariable(value = "tcpId")
                                  ULong tcpId,
                                  @RequestBody
                                  TeachConPrjAuditDTO teachConPrjAuditDTO) {

        teachConPrjService.auditProject(tcpId, teachConPrjAuditDTO);
        return R.ok();
    }

    /**
     * 分配绩点
     *
     * <p>
     * 只有审核通过的项目可以分配绩点,可分配的项目总绩点以管理员最终绩点评分为准
     *
     * @param tcpId 重点建设项目id
     */
    @PostMapping(value = "project/point/assign/{tcpId}")
    public R<String> assignPoint(
            @PathVariable(value = "tcpId")
            ULong tcpId,
            @RequestBody
            @NotEmpty(message = "不可分配空绩点")
            List<@Valid TcpPointAssignRecordDTO> tcpPointAssignRecordDTOS
    ) {

        teachConPrjService.assignPoint(tcpId, tcpPointAssignRecordDTOS);
        return R.ok();
    }


    /**
     * 查询项目绩点分配情况
     *
     * @param tcpId 重点建设项目id
     */
    @GetMapping(value = "project/point/list/{tcpId}")
    public R<List<TcpPointAssignRecordVO>> listTcpPointAssignRecords(@PathVariable(value = "tcpId") ULong tcpId) {

        List<TcpPointAssignRecordVO> tcpPointAssignRecordVOList = teachConPrjService
                .listTcpPointAssignRecords(tcpId);
        return R.ok(tcpPointAssignRecordVOList);
    }


    /**
     * 查询对应项目的所有审核记录
     * 并以审核等级的字典数据id分组
     *
     * @param tcpId 申报项目id
     */
    @GetMapping(value = "project/audit/records/{tcpId}")
    public R<Map<ULong, List<TcpAuditRecordVO>>> listTcpAuditRecords(@PathVariable(value = "tcpId")
                                                                     ULong tcpId) {
        Map<ULong, List<TcpAuditRecordVO>>
                tcpAuditRecordGroupVOs = teachConPrjService.listTcpAuditRecordGroupVOs(tcpId);

        return R.ok(tcpAuditRecordGroupVOs);
    }

    /**
     * 查询对应项目的负责人信息
     */
    @GetMapping(value = "project/leaders/{tcpId}")
    public R<List<UserSimpleVO>> listProjectLeaders(
            @PathVariable(value = "tcpId")
            ULong tcpId) {

        List<UserSimpleVO> projectLeaders = teachConPrjService.listProjectLeaders(tcpId);
        return R.ok(projectLeaders);
    }

    /**
     * 根据学院和年度导出对应申报后的所有重点建设项目基本信息的EXCEL
     * 并分成对应模板的表
     */
    @GetMapping(value = "project/collegeGPACollectExport")
    @Anonymous
    public void exportCollegeTeachConPrj(HttpServletResponse response,
                                         @NotNull(message = "学院id不可为空")
                                         @RequestParam(name = "collegeId")
                                         ULong collegeId,
                                         @RequestParam(name = "tcpDbycId")
                                         @NotNull(message = "归属年度信息id不可为空")
                                         ULong tcpDbycId) {
        teachConPrjService.exportCollegeTeachConPrj(collegeId, tcpDbycId, response);
    }

    /**
     * 绩点汇总统计导出
     */
    @GetMapping(value = "project/exportPointList")
    @Anonymous
    @SneakyThrows
    public void exportPointList(HttpServletResponse response,
                                @RequestParam(name = "tcpDbycId", required = false)
                                ULong tcpDbycId) {
        List<PointExcelVO> pointExcelVOList = teachConPrjService.getPointExcelVOList(tcpDbycId);
        Year belongYear = null;
        if (tcpDbycId != null) {
            belongYear = belongYearConfigDAO.fetchOneByTcpDbycId(tcpDbycId)
                    .getBelongYear();
        }
        String belongYearStr = tcpDbycId != null ? belongYear.toString() + "年" : "往年所有";
        String fileName = belongYearStr + "绩点汇总统计";
        ExportParams params = new ExportParams(null, fileName, ExcelType.HSSF);
        params.setHeight((short) 30);
        params.setColor(HSSFColor.HSSFColorPredefined.GREEN.getIndex());

        //文档输出
        try (Workbook workbook = ExcelExportUtil.exportExcel(params, PointExcelVO.class, pointExcelVOList)) {
            response.setHeader("content-disposition", "attachment;filename="
                    + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + ".xls");
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            try {
                log.error("导出内部异常:{}", objectMapper.writeValueAsString(e.getMessage()));
            } catch (JsonProcessingException ignored) {

            }
            throw new ServiceException("导出内部异常,请联系管理员");
        }

    }


}
